#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time
import socket
import select

from worker import WorkerThread
from table import *
from card import *
from player import *

class GameServer(object):
    '''游戏服务端，管理网络、游戏及玩家信息，向Player发出指令（调用Player），由Player响应操作'''
    
    #服务器状态值
    NOTREADY, WAITING, RUNNING=range(3)
    def __init__(self):
        #牌桌资源
        self.table=Table()
        #玩家列表
        self.players=[]
        #空闲玩家列表，用于维护未连接的网络玩家
        self.idlePlayers=[]
        #本地玩家，只能有一个
        #TODO:initial a test player
        self.localPlayer=None
        #服务器状态
        self.state=GameServer.NOTREADY
        #监听套接字，用于监听客户端连接
        self.servSock=None
    
        #工作线程，用于处理网络请求
        self.workerThread=WorkerThread()
    
        #待配置成员参数
        
        #游戏逻辑
        self.game=None
        #玩家数
        self.playerCount=4
        #网络玩家数
        self.netPlayerCount=0
        #网络监听地址
        self.listenAddress=''
        #网络监听端口
        self.listenPort=1234
        
        #更新配置
        self.updateConfig()

    def updateConfig(self):
        '''从配置文件更新配置'''
        #监听超时
        self.listenTime=INI.server.listenTime
        #等待准备状态超时
        self.waitTime=INI.server.waitTime

    def setState(self, state):
        '''设置服务器状态'''
        self.state=state
    
    def getState(self):
        '''获取服务器状态'''
        return self.state

    def setGame(self, game):
        '''连接服务器和游戏'''
        self.game=game
        self.game.server=self
    
    def setLocalPlayer(self, player):
        '''设置本地玩家'''
        self.localPlayer=player
    
    def orderPlayers(self):
        '''按id顺序排列玩家'''
        self.players.sort(key=lambda x:x.info['id'])
    
    def configure(self, **info):
        '''配置服务器参数'''
        arg=info.get('game')
        if arg is not None:
            self.setGame(arg)
        
        arg=info.get('cardPack')
        if arg is not None:
            self.table.cardPack=arg
            
        arg=info.get('cardBase')
        if arg is not None:
            self.table.cardBase=arg
        
        arg=info.get('localPlayer')
        if arg is not None:
            self.setLocalPlayer(arg)
        
        arg=info.get('playerCount')
        if arg is not None:
            self.playerCount=arg
        
        arg=info.get('netPlayerCount')
        if arg is not None:
            self.netPlayerCount=arg
        
        arg=info.get('listenAddress')
        if arg is not None:
            self.listenAddress=arg
        
        arg=info.get('listenPort')
        if arg is not None:
            self.listenPort=arg
    
    def serveForNet(self):
        '''开启网络服务等待NetPlayer连接，新线程'''
        
        #绑定并监听端口
        try:
            self.servSock=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.servSock.bind((self.listenAddress, self.listenPort))
            self.servSock.listen(1)
            self.showMessage('Server start listening')
        except:
            self.setState(GameServer.NOTREADY)
            self.showMessage('Network error!')
            
        
        while self.getState()==GameServer.WAITING:
            #循环等待监听套接字可读（即有连接请求），超时默认2秒
            rs, ws, es = select.select([self.servSock], [], [], self.listenTime)
            
            #接受网络请求
            if self.servSock in rs:
                sock, hostport=self.servSock.accept()
                #从空闲玩家列表中取出可用的网络玩家，置予连接套接字并加入到玩家列表
                if len(self.idlePlayers)>0:
                    player=self.idlePlayers.pop(0)
                    player.setSocket(sock)
                    self.players.append(player)
                    player.exchangeInfo(player.info)
                    self.notifyAll([player.info['id'], ENTER, player.info])
                else:
                    #服务器满人不给连接
                    sock.send(EXIT)
                    sock.close()
        
        #结束前关闭套接字
        if self.servSock:
            self.servSock.close()
        
        self.showMessage('Server stop listening')
        
    def checkReady(self):
        '''检查各player是否准备好（建立连接并设置准备）'''
        
        #检测断开连接的网络玩家，将其移至空闲列表
        for player in self.players:
            if type(player)==NetPlayer and not player.checkConnected():
                player.do(RESETDATA)
                self.players.remove(player)
                self.idlePlayers.append(player)
        
        #检测各玩家的准备状态(网络玩家getReady需要从客户端获取)
        ready=True
        for player in self.players:
            cmd, rstate=player.getReady()
            #TODO:test
#            print 'check ready ', player.info['id'], rstate
            if not rstate:
                ready=False
#                break
            
#        print '--------------------------------------'
        return ready and len(self.players)==self.playerCount
    
    def waitReady(self):
        '''等待各player准备好后返回，默认每2秒检测一次，针对网络玩家'''
        self.showMessage('Waiting players ready') 
        while not self.checkReady():
            if self.getState()!=GameServer.WAITING:
                self.showMessage('Server not ready!') 
                return
            time.sleep(self.waitTime)
        self.showMessage('All players ready') 
        self.setState(GameServer.RUNNING)
    
    def create(self):
        '''服务端创建游戏'''

        if self.workerThread.isAlive():
            self.workerThread.stop()
            self.reset()
            self.showMessage('Server not ready!')
            return

        #设置服务器状态为WAITING，表示等待各玩家准备游戏
        self.setState(GameServer.WAITING)
        
        #TODO:下一id编号，id决定各玩家在牌桌的位置，暂时不可修改
        nextid=0
        
        self.localPlayer.do(RESETDATA)
        
        #添加本地玩家
        player=self.localPlayer
        player.setInfo({'id':nextid})
        self.players.append(player)
        self.notifyAll([player.info['id'], ENTER, player.info])
        nextid+=1

        #添加机器人玩家
        for i in range(self.playerCount-self.netPlayerCount-1):
            player=BotPlayer({'id':nextid})
            self.players.append(player)
            player.exchangeInfo(player.info)
            self.notifyAll([player.info['id'], ENTER, player.info])
            nextid+=1
        
        #添加网络玩家
        if self.netPlayerCount>0:
            for i in range(self.netPlayerCount):
                self.idlePlayers.append(NetPlayer({'id':nextid}))
                nextid+=1
            #开启监听线程
            
            if self.workerThread.isAlive():
                self.workerThread.stop()
                self.reset()
                self.showMessage('Network not ready!')
            else:
                self.workerThread=WorkerThread()
                self.workerThread.setMethod(self.serveForNet, ())
                self.workerThread.start()

    def reset(self):
        '''重置服务器'''
        self.setState(GameServer.NOTREADY)
        self.table.reset()
        self.players=[]
        self.idlePlayers=[]
        if self.servSock:
            self.servSock.close()
        self.servSock=None
        self.showMessage('Reset server')

    def showMessage(self, msg):
        '''显示通告消息'''
        if self.localPlayer:
            self.localPlayer.ui.updateData(SHOWMESSAGE, msg)

    def start(self):
        '''开始游戏'''
        if self.getState()==GameServer.NOTREADY:
            return
        #游戏开始前需正确排列玩家
        self.orderPlayers()
        try:
            self.game.begin()
        except Exception, e:
            print e
            return

    def notifyAll(self, data):
        '''通知所有玩家更新数据'''
        for player in self.players:
            player.do(UPDATEDATA, data)
        
        #延迟法防止粘包，已不需要
        #sleep(0.05)

if __name__ == '__main__':
    pass
